home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d1
/
bastips2.arc
/
BASICNTS.TXT
< prev
next >
Wrap
Text File
|
1988-11-29
|
45KB
|
993 lines
Safe Zones in IBM BASIC
(COMPUTE! Magazine July 1986)
There is a way to store a few characters or flags in the PC's
memory that will survive the BASIC RUN command. BASIC's CLEAR command
gives you the ability to create a safe area of RAM of almost any size.
Besides deleting all variables, CLEAR controls the amount of memory
available to BASIC. By adding a command and a parameter to the CLEAR
command, you can make the BASIC workspace smaller than usual, reserving
the extra memory for yourself. The workspace is initially 65,536 bytes
but it's easy to reserve some memory at the top of that space. Use
this format:
CLEAR ,workspace
where workspace is a number less than 65536. To calculate the correct
value, subtract from 65536 the number of bytes you want to protect.
For instance, the command, CLEAR ,65280 reserves the last 256 bytes
(65536 - 256 = 65280) of BASIC workspace for your use. When you type
RUN after a CLEAR statement like this, the size of the workspace is
reset to its default but the data in the reserved area is not affected.
As long as the next program begins with a similar CLEAR statement, it
can PEEK into the reserved area and find the values that the previous
program POKEd there. Here's a simple program that stores some values
in a 256-byte reserved area:
10 CLEAR ,65280
20 FOR A=0 TO 255
30 POKE A+65280,A
40 NEXT
After you run the program, enter and run this program to read the
stored values back:
10 CLEAR ,65280
20 FOR A=0 TO 255
30 PRINT PEEK(A+65280)
40 NEXT
-----------------------------------------------------------------
Selective BSAVE/BLOAD
(PC Magazine Vol 5 No 13 July 1986 User-to-User)
Most users who BSAVE and BLOAD BASICA screens do so a full screen
at a time, but it can be very handy to do it in smaller pieces. The
LITLBSAV.BAS program BSAVEs a little piece of the screen (three lines)
and then lets the user BLOAD it back in various places up and down the
screen. This technique works very well off a RAMdisk or hard disk but
is slow when run from a floppy.
Editor's Note: The program was modified so it BSAVEd three lines
(a line of text with a blank line above and below) and let users move
the BSAVEd block up and down the screen. (Including blank lines above
and below the printed line effectively erases existing printed lines
on-screen.) In line 120 the program determines whether the system is
monochrome (where PEEK(1097)=7) or not, and in line 130 sets the
segment to &HB800 for color or &HB000 for mono. Color systems offer
four screen pages, 0 through 3. If you have a color system, you can
increase the upper limit in line 200 to 3680 and make the text
temporarily "disappear."
The nice thing about this technique is that it lets you "pop" up
text onto existing screens. However, it won't restore the existing
part of the screen it covers over. Still, by BSAVEing portions of
screens and BLOADing them at the appropriate locations, you save disk
space adn make the BLOAD operation a little faster.
Since color screen memory is not dual-ported (as mono memory is),
you'll see "chatter" or "snow" while the BLOAD is occurring. Most snow
is white, so by setting a white (7) background most of it is covered
up. This will run slower on a disk system unless you hit the Up and
Down Arrow keys rapidly enough to keep the floppy spinning constantly.
These days you can buy slow hard disks for a lot less than $500. Or
stock up on system RAM and try this in a RAMdisk.
BSAVCALC.BAS calculates the offset and length for BSAVEs (and the
offset for BLOADs) less than a full screen in size. The PC text screen
memory is arranged so that each character takes up 2 bytes -- one
representing the actual character, and one for the character's
attribute. The default text screen is 80 characters wide, so each
80-wide lien in memory takes up 160 bytes. Color memory begins at
segment &HB800, mono memory at &HB000. You tell BASICA which segment
you want with the statement DEF SEG=&HB800 or DEF SEG=&HB000. BSAVE
needs to know three things -- the filename it will use to store the
screen on your disk, the "offset" (distance in bytes up from the
segment specified by DEF SEG), and the length of the file to save.
Line 1 goes from offset 0 to offset 159, line 2 from 160 to 319, etc.
All BLOAD needs to know is the filename and offset, not the length.
100 'LITLBSAV.BAS
110 DEFINT A-Z:CLEAR:S$=STRING$(4,205)
120 DEF SEG=0:IF PEEK(1097)=7 THEN SG=&HB000 ELSE SG=&HB800
130 DEF SEG=SG:KEY OFF:SCREEN 0,0:COLOR 4,7,6:CLS:LOCATE 2,1,0
140 PRINT S$;" This BLOADs a line at a time (hit ";CHR$(24):" and ";
150 PRINT CHR$(25);" keys to move, or ESC to end) ";S$
160 BSAVE "TEST.SCR",0,480:CLS:S=3680:GOTO 210
170 I$=INKEY$:IF I$="" THEN 170 ELSE IF I$=CHR$(27) THEN LOCATE 1,1:END
180 I=INSTR("HP",RIGHT$(I$,1)):IF I=0 OR LEN(I$)=1 THEN BEEP:GOTO 210
190 IF I=1 THEN IF S<0 THEN BEEP:GOTO 170 ELSE S=S-160:GOTO 210
200 IF S>3520 THEN BEEP:GOTO 170 ELSE S=S+160
210 BLOAD "TEST.SCR",S:GOTO 170
- - - - -
100 'BSAVCALC.BAS
110 DEF FNST$(Z)=MID$(STR$(Z),2+(Z<0)):Q$=CHR$(34):CLS
120 PRINT "Pick one: 1 - BSAVE 2 - BLOAD (1 or 2)"
130 I$=INKEY$:IF I$="" THEN 130 ELSE IF I$=CHR$(13) THEN END
140 IF INSTR("12",I$)=0 THEN 130 ELSE I=VAL(I$)
150 IF I=2 THEN B$="BLOAD " ELSE B$="BSAVE "
160 PRINT CHR$(30);B$;"information:";STRING$(20,32)
170 INPUT "Enter a start line from 1-25: ",S1
180 IF S1<1 OR S1>25 THEN BEEP:GOTO 170
190 IF I=2 THEN PRINT:PRINT "For line";S1:GOTO 230
200 INPUT "Enter a stop line from 1-25: ",S2
210 IF S2<1 OR S2>25 OR S2<S1 THEN BEEP:GOTO 200
220 PRINT:PRINT "For line(s)";S1;"to";S2
230 OFFSET=(S1-1)*160:LENGTH=(S2*160)-OFFSET
240 PRINT "Offset =";OFFSET:IF I=2 THEN 260
250 PRINT "Length =";LENGTH
260 PRINT "Syntax = ";B$;Q$;"filename";Q$;",";
270 PRINT FNST$(OFFSET);:IF I=2 THEN 290
280 PRINT ",";FNST$(LENGTH);
290 PRINT:PRINT:PRINT STRING$(40,61):PRINT:GOTO 120
-----------------------------------------------------------------
Value Added
(PC Magazine Vol 5 No 13 July 1986 User-to-User)
In the IBM BASICA documentation for VAL, the example at the bottom
of the page correctly extracts the house number from an address:
PRINT VAL("3408 SHERWOOD BLVD.")
3408
However, if the address happens to be "3408 E 9th Street," VAL returns
the number 3048000000000, as it interprets the "E" as the exponential
part of the number. This also occurs with a D.
You can prevent trouble by putting periods after the E or D.
PRINT VAL("3408 E. 9th Street")
works properly.
-----------------------------------------------------------------
Automatic IBM Screen Printing
(COMPUTE! Magazine August 1986)
You can add a Print Screen function to any program by POKEing a
tiny machine language into a reserved space at the top of BASIC's
memory area. The ML just executes INT5:RETF to call the Print Screen
routine and returns to BASIC.
When incorporating this routine into your program(s), the line
with the CLEAR statement must be the first line in your program.
Otherwise, any previously defined variables will be erased. Once the
machine language is POKEd into memory, your program can execute the
statement CALL PRTSC to make a printout.
100 CLEAR ,&HFFF0:PRTSC=&HFFF0
110 DEF SEG:FOR X=0 TO 2:READ N:POKE X+PRTSC,N:NEXT
120 DATA &HCD,&H05,&HCB
200 CALL PRTSC
-----------------------------------------------------------------
Batch Files with IBM BASIC
(COMPUTE! Magazine August 1986 by Lawrence H. Bannister)
IBM users know that you can save time by using the batch commands
of DOS to perform a sequence of DOS commands automatically. But the
austere language of DOS provides only three variations of one simple
IF statement and has no practical way at all of manipulating strings
or performing arithmetic. It's difficult to write a batch file that
creates neat screen displays, makes logical branches, allows user
input, and traps errors.
A more flexible technique is to call DOS commands or even batch
files from with a BASIC program. This frees you from the limitations
of batch files and takes advantage of the string and arithmetic
functions of BASIC.
You can call DOS from BASIC as often as you wish by using the
SHELL command found in IBM BASICA. Although it is not documented,
this command is implemented in version 2.1 or higher of DOS. Aside
from a few small problems to be avoided, its possibilities are limited
only by your imagination.
To demonstrate some of these possibilities, the BASIC Batch Demo
program below displays two menus of options, interprets the user's
responses, and then calls a variety of DOS routines in several
different ways. The Batch File for Demo is a short batch file that
is required as part of this demonstration.
When you run the BASIC program, it shows a menu offering four
choices:
MENU A:
1. Show system date
2. Show system time
3. Show system date and time
4. None of the above
Enter your choice:
When the user presses a key, the program checks to see if the
keypress was 1, 2, 3, or 4, and if so, uses the SHELL command to call
the appropriate DOS function: DATE, TIME, or the batch file that calls
both DATE and TIME.
When DOS returns control to BASIC, the program displays a second
menu:
MENU B:
1. Run Checkdisk
2. Show Disk Directory
3. None of the above
Enter your choice:
This is similar to the first menu, except this time the program
calls a DOS function that requires a parameter to be passed to the DOS
command line. The BASIC program asks the user for the necessary
information, then concatenates the appropriate command-line string.
Notice that the SHELL command can pass either a literal string,
as done in the first menu, or a string variable, as in the response
to the second menu.
There are two considerations to keep in mind when using this
technique. First, make sure your system has enough memory. Although
DOS, BASICA, and your BASIC program can be loaded into a machine with
as little as 64K of RAM, you won't have much memory left over to do
anything very useful. At least 92K RAM is desireable, because DOS and
BASICA together use about 90K if that much is available. You need
still more memory if you also want to run a batch file that calls a
lengthy program like EDLIN.
Second, be sure not to create a sequence that is reentrant or
recursive. For example, the result will be unpredictable if you BASIC
program calls a batch file that, in turn, calls BASIC. Reentrant
sequences of this nature are apt to cause a system crash that can be
remedied only by turning off the power.
A minor aggravation is that DOS scrolls 25 lines on the screen
while BASIC scrolls only 24 lines due to the function key display on
the 25th line. Furthermore, BASIC and DOS each maintain an independent
pointer to the screen position of the cursor. These differences can
cause BASIC PRINT statements to overwrite something that DOS has just
printed.
To avoid this problem, always start the BASIC program with the
KEY OFF command to turn off BASIC's function key display. Then use a
CLS command each time that DOS returns control to BASIC, or, as shown
in the sequence following the second menu in the BASIC Batch Demo
program, surround the SHELL commands with LOCATE 24,1 statements and
two blank PRINT lines to ensure that both DOS and BASIC always start
scrolling from the bottom of their own screens.
BASIC Batch Demo Program:
1000 'Procedure Description
1010 'Clear screen and display a menu offering four choices
1020 'Wait for user response
1030 'If user response is not valid
1040 'Then : display error message and repeat the menu
1050 'Else :
1060 'Invoke the selected DOS function or Batch file
1070 'Clear screen and display a second menu
1080 'Wait for user response
1090 'If user response is not valid
1100 'Then : display error message and repeat the menu
1110 'Else :
1120 'Invoke the selected DOS function or program
1130 '
1140 '
1150 KEY OFF:CLS
1160 GOTO 1210
1170 '
1180 PRINT 'Error message
1190 PRINT "* * * * * * * ILLEGAL RESPONSE ^ REDO"
1200 '
1210 PRINT:PRINT "MENU A:" 'Display menu
1220 PRINT:PRINT "1. Show system date"
1230 PRINT:PRINT "2. Show system time"
1240 PRINT:PRINT "3. Show system date and time"
1250 PRINT:PRINT "4. None of the above"
1260 PRINT:PRINT:INPUT "Enter your choice: ",A$
1270 '
1280 IF A$="" THEN 1180 'Check response
1290 IF ASC(A$)<49 THEN 1180
1300 IF ASC(A$)>52 THEN 1180
1310 '
1320 IF A$="1" THEN SHELL "DATE"
1330 IF A$="2" THEN SHELL "TIME"
1340 IF A$="3" THEN SHELL "PROG2"
1350 '
1360 CLS
1370 GOTO 1410
1380 '
1390 PRINT "* * * * * * * ILLEGAL RESPONSE ^ REDO"
1400 '
1410 PRINT:PRINT "MENU B:"
1420 PRINT:PRINT "1. Run Checkdisk"
1430 PRINT:PRINT "2. Show Disk Directory"
1440 PRINT:PRINT "3. None of the above"
1450 PRINT:PRINT:INPUT "Enter your choice: ",A$
1460 PRINT
1470 '
1480 IF A$="" THEN 1390
1490 IF ASC(A$)<49 THEN 1390
1500 IF ASC(A$)>51 THEN 1390
1510 '
1520 IF A$="3" THEN 1630
1530 IF A$="1" THEN B$="CHKDSK"
1540 IF A$="2" THEN B$="DIR"
1550 INPUT "Enter drive letter: ",C$
1560 IF C$="" THEN 1550
1565 X=ASC(C$+CHR$(0)):IF X<65 OR X>66 THEN 1550
1570 D$=B$+LEFT$(C$,1)+":"
1580 LOCATE 24,1
1590 IF A$="1" THEN GOSUB 1710
1600 SHELL D$
1610 PRINT:PRINT
1620 '
1630 PRINT "End of BASICA program, returning to SYSTEM"
1640 PRINT
1650 PRINT TAB(20) "Normally would return to SYSTEM here,"
1660 PRINT TAB(20) "but for debug and demo purposes the"
1670 PRINT TAB(20) "program will restart after a delay"
1680 FOR I=1 TO 5000:NEXT I:RUN
1690 '
1700 '
1710 PRINT
1720 PRINT "WARNING: You will get error message `Bad command ...'"
1730 PRINT " if the called program is not on "
1740 PRINT " the disk in the default drive"
1750 RETURN
Batch File for Demo:
ECHO OFF
ECHO .
REM Display the system date
DATE
ECHO .
REM Display the system time
TIME
:ENDPROG2
-----------------------------------------------------------------
BASIC Debugging
(PC Magazine August 1986 User-to-User)
BASIC is great for interactive programming, but its debugging
tools are quite primitive. One of the most irritating limitations is
that when you make a simple correction to a single line (even a REMark)
BASIC flushes all your variables, closes all your files, and forces you
to start the program over to test the correction.
When the interpreter finds an error, it prints an error message
and halts the program. In many cases, you could continue running the
program if only you could re-enter the offending line and re-execute
it. To make such on-the-fly corrections, examine the erroneous line
with the LIST command. (The problem line will already be displayed if
it contains a syntax error.) Then type the following command in
direct mode:
CHAIN MERGE "CON",ERL,ALL
The cursor will drop down to the next line and wait for keyboard
input. Next, rekey the bad line, and press Enter and then Ctrl-Z and
then Enter again. The program will continue where it left off. The
next time you list or save the program, it will contain the repaired
program line.
Another tip on smart BASIC debugging is to avoid error traps (ON
ERROR GOTO) unless they are absolutely necessary. They tend to hide
errors that need to be caught, and you will find yourself unable to
get to the root of a malfunction. Programs can trap errors right at
the source, and then turn error trapping off as soon as possible.
For example:
100 'Print report
110 ON ERROR GOTO 130
120 GOTO 150
130 PRINT "Printer ERROR. Hit a key."
140 WHILE INKEY$="":WEND:RESUME
150 LPRINT "ABC Company Report"
160 ON ERROR GOTO 0
170 '...print rest of report ....
This example assumes that any printer errors will surface during
the printing of the first line of a report. The error trap itself
resides directly above the possible error, and error trapping is on
only during the printing of that line. Use a similar layout when
opening files. Printer and disk I/O are about the only places that
an error trap is really needed. You can write program code to test
for any other potential problems without resorting to BASIC's error
handling.
Editor's Note: Using CHAIN MERGE "CON" to fix a BASIC problem
without shutting down the active program is a handy trick. Your
cursor may temporarily disappear while you're entering the new line,
and you may have to hit the Esc key to erase a message on the screen
before you type in the CHAIN MERGE... command, but the technique can
save a tremendous amount ot time. Note that while this will correct
the problem line in memory, be sure to save the file to disk to make
the correction permanent.
In the report-printing routine, you might want to test the error
that BASIC catches with an IF ERR=25 THEN... or IF ERL=150 THEN... to
make sure that the actual problem isn't falsely reported as a printer
error when it's caused by something else. However, it is right to
trap all the usual errors by writing thorough code, not by skimping
on traps and waiting for a mistake to fall through to an ON ERROR
statement.
-----------------------------------------------------------------
Refreshing PAUSE
(PC Magazine August 1986 User-to-User)
To pause for a keystroke in BASICA, most programmers use either
10 A$=INEKY$:IF A$="" THEN 10
or
10 WHILE INKEY$:WEND
A more natural way is to create a machine language subroutine at the
beginning of your program and then call it whenever required. Simply
insert the following code at the start of any program:
0 CLEAR,5888
1 DEF SEG=5888
2 FOR X.=0 TO 6
3 READ Y.
4 POKE X.,Y.
5 NEXT
6 PAUSE=0
7 DATA 80,180,7,205,33,88,203
and then adda a
100 CALL PAUSE
(substituting the appropriate line number for the 100) whenever you
want to wait for a keystroke. The example here takes up seven lines,
but you can use colons to concatenate it all to a single line starting
with 0 and save the line as an ASCII file, then merge this file into
any of your existing programs. The X. and Y. variables and line number
0 are uncommon so that they don't interfere with ones already in your
programs.
The key you hit to break the pause is not stored in the keyboard
buffer after the program execution continues. If you need to read the
key, change the "7" to a "1" in the DATA statement in line 7.
Editor's Note: This may be more natural than the usual methods,
but it doesn't really work any better and won't compile as is. If you
try it and do want the keystroke to print, after changing the 7 to 1
in the DATA statement, follow the CALL PAUSE with a
200 PRINT INKEY$
(substituting the appropriate line number for the 200).
-----------------------------------------------------------------
Compaq Unprotection
(PC Magazine August 1986 User-to-User)
It's simple to modify the technique for unprotecting BASIC
programs described in PC Mag Vol 4 No 25 User-to-User and PC Mag Vol 5
No 10 PC Tutor to work on non-IBM versions of BASIC. Instead of IBM's
location 1124, use 1228 for Compaq BASIC 2.11, and 1433 for Compaq
BASIC 3.11. If the location is included in the BSAVE ooperation, you
may omit it from the BLOAD. Other non-IBM, non-Compaq versions of
MS-BASIC may use entirely different locations.
Editor's Note: "Protecting" a BASIC file by saving it with the
",p" option doesn't really do much other than prevent naive users from
listing the source code. The technique to remove the flimsy protection
is to get into BASIC and typing:
BSAVE "UN.P",1124,1
(substituting location 1228 or 1433 if you're using Compaq BASIC 2.11
or 3.11, respectively). If you every try to list a BASIC program and
see an "Illegal function call" message, just type:
BLOAD "UN.P"
At this point you should be able to list the source code. If not, make
sure you tried the proper offset (1228 or 1433) for the BASIC version
you're using. Then resave the formerly protected BASIC program to
remove the effects of the ",p" permanently.
-----------------------------------------------------------------
STRING$ and CHR$
(COMPUTE! Magazine September 1986)
The statement PRINT STRING$(15,32) has exactly the same effect as
PRINT " " (15 spaces). STRING$ can be used where any
long series of identical characters is needed. For instance, PRINT
STRING$(40,46) prints a line consisting of 40 dots.
You can also do the same thing through concatenation. To create
a string consisting of 30 spaces, for instance, use:
SP$=" "
FOR J=1 TO 30
SP$=SP$+CHR$(32)
NEXT
This construction is easy to type and requires only a few more
characters than printing the string in literal form.
-----------------------------------------------------------------
BASIC Configuration
(PC World September 1986 Star-Dot-Star)
A short BASIC program can define BASIC's function keys and then
erase itself from memory. A short batch file can start BASIC and run
this program automatically so that your custom function key assignments
are in place.
Defining the function key settings in this manner also lets you
use the following time-saving trick. Whenever you write a BASIC
program, always put a comment on line 1 beginning with the program's
name enclosed in quotes. Combining this step with the F10 definition
show in BSTART.BAS enables you to save a program anytime with one
quick keystroke.
The first part of F10's definition, "LIST 1"+CHR$(13), simply
lists the first line of the current program -- the line containing the
program's name. The two CHR$(30) characters move the cursor back to
the beginning of the listed line. SAVE overwrites the line number and
the apostrophe, leaving the file name in quotation marks intact. The
last CHR$(13) simulates pressing Enter, executing the SAVE command
using the supplied file name.
This technique should be a boon to anyone who issues SAVE commands
frequently, since it reduces that task to a single keystroke. If you
prefer to save your programs in ASCII format you can place the ,A after
whatever file name you specify.
-----------------------------------------------------------------
IBM Custom Characters
(COMPUTE! Magazine September 1986)
You can redefine the character set on the IBM PC; however, there
are a couple of restrictions. Redefined characters must be printed on
one of the graphics screens to be seen, and only the upper half of the
character set (characters 128-255) can be changed. The following
program shows how to redefine CHR$(128) as an alien shape. It displays
the custom character on SCREEN 1.
10 DEF SEG=0
20 POINTER=&H7C 'POINTER &H110 for characters 0-127 on the PCjr only
30 FOR VECTOR=0 TO 3:OLDVEC(VECTOR)=PEEK(POINTER+VECTOR):NEXT
40 DEF SEG=&H1700
50 FOR DOTPOS=0 TO 7:READ DOT DATA:POKE DOTPOS,DOTDATA:NEXT
60 DEF SEG=0:
70 SCREEN 1:CLS
80 FOR VECTOR=0 TO 2:POKE(POINTER+VECTOR),0:NEXT:POKE POINTER+3,&H17
90 PRINT CHR$(128)
100 FOR VECTOR=0 TO 3:POKE(POINTER+VECTOR),OLDVEC(VECTOR):NEXT
110 DATA 60,126,90,126,60,36,66,129
You make the computer look to RAM rather than ROM for its character
data. If you have at least 128K of RAM in your PC, memory above 96K is
unused by BASIC and is thus a safe place to store the custom character
data. Line 40 of the program accesses this area with the statement
DEF SEG=&H1700. In line 50, the program puts the alien shape data in
the area beginning at &H1700. Line 110 contains the data.
To make the PC fetch its character data from the segment at &H1700,
we must change certain pointers at the bottom of memory. These pointers
are four bytes long. The first two bytes represent an offset to the
segment address contained in the third and fourth bytes. The pointer
to the data for the built-in graphics and foreign language characters
(numbered 128-255) is at locatino &H7C. Since the program redefines a
character in this range -- CHR$(128) -- we've used this pointer value
in line 20. On the PCjr, you can redefine characters in the range
0-127 using the pointer at location &H110. In order to access either
character data pointer, you must set DEF SEG to zero since the pointers
are at the bottom of memory. The program does this in lines 10 and 60.
Before the program ends, the character data pointers must be
restored to their default values. If you end the program with the
character pointers still modified, the computer can't recognize the
custom characters and will fail to respond to any commands. Before
modifying the characters, save the default character set pointers
(line 30). When you're done printing the custom characters, restore
the pointers to their original values (line 100).
-----------------------------------------------------------------
Identifying Displays
(PC Magazine Vol 5 No 16 Sept 30, 1986 PC Tutor)
A user develops applications with the BASIC interpreter and
compiles them with Microsoft QuickBASIC. He uses a technique to blank
the screen while text is being written to it. This results in a nice,
professional-looking video screen that flashes on all at once, rather
than visibly being drawn one line at a time. To turn the display off,
use the statement:
OUT 984,1
and to turn it back on:
OUT 984,41
This works perfectly with an IBM or compatible color graphics
adapter. The problem is that the programs must also run on some
Hercules Graphics Cards (and Hercules clones), and the technique
doesn't work with these boards. Different video pages are also used
in the programs, and these, too, are ignored by the Hercules card.
Editor's Note: This technique won't work on regular IBM Mono
Adapters, either. The port being manipulated is the "Mode Control
Port Register," which has a different address on color adapters and
monochrome adapters, including the Hercules Graphics Card. The Control
Port for monochrome displays is at address 952 rather than 984. (In
hex, these addresses are 3B8 and 3D8.)
You can blank an IBM Monochrome Adapter or Hercules Card with:
OUT 952,1
and unblank it with:
OUT 952,41
but that's not the best way to do it.
The control port address is always 4 higher than the I/O address
of the 6845 video chip. That port address is a word (2 bytes) stored
at the hex address 0040:0063 in the BIOS data area. So, you can
define a variable for the Control Port thus:
DEG SEG=&H40
CTRLPORT=4+256*PEEK(&H64)+PEEK(&h63)
Now you can simply use the variable CTRLPORT instead of 984 or 952.
You won't be able to use separate video pages on an IBM Monochrome
Adapter or the Hercules Graphics Card, however; so unless you want to
write alternative code for the monochrome boards, it's easier to avoid
using video pages altogether. (If you must use video pages, you can
still use the value of CTRLPORT to also identify the type of adapter.)
In general, however, the best way for your programs to identify
the video display is to ask the user on-screen. This is nothing to
be ashamed of. You'll find that most software that does anything
beyond plain vanilla text output requires some sort of installation
program. Some really big-league stuff like Microsoft Word can adapt
to different displays without being told, but then we're talking about
a 44K WORD.COM program (version 3.0) that identifies displays and
provides drivers for them. We're also talking about problems by
experts in the field. Further, we're about to see a real explosion
in video adapters, and it's going to get tougher and tougher to write
programs that work with all of them. The EGA is just the beginning.
(The above technique of blanking the screen won't work on an EGA, but
it won't do any harm, either.) This is one reason why the graphics
device interface of Microsoft Windows is so important to the future
of the PC. Windows takes on the responsibility of dealing with the
hardware so that you can concentrate on the program.
-----------------------------------------------------------------
BSAVE Image Arrays to Disk
(PC World October 1986 The Help Screen)
Recording a BASIC image array in a disk file and reading that
file to set an image variable is simpler than using GET and PUT. To
save an image array to disk, issue the DEF SEG statement to set BASIC's
data segment as the current memory segment, and execute the BSAVE
(binary save) command.
The BSAVE command, which saves any portion of memory to disk,
requires three parameters: the filespec of the file being saved, the
offset (number of bytes) into the current memory segment where the
first byte of data representing the image begins, and the number of
bytes to be saved.
The filespec requires a file name, but it can include a drive
specifier and, with BASIC 2.0 and later versions, a path. The offset
should point to the beginning of the image array variable. You
accomplish this by specifying the array's first element, (0), with the
VARPTR function. You already know the size of the variable array
because you had to calculate the number of bytes that the image array
required to properly DIMension the array. In this example, the image
is 34 bytes. Because a single-precision array dedicates 4 bytes per
element, a nine-element array will reserve sufficient space.
BSAVE.BAS also demonstrates how to load a saved image array.
Issue a DEF SEG statement to set BASIC's data segment as the current
memory segment, then execute the BLOAD (binary load) command to put
the image data into memory. BLOAD requires just two parameters: the
filespec and the offset of the current memory segment where the image
file should be placed. Point to the beginning of the image array
variable with the aid of the VARPTR function.
BSAVE.BAS:
10 SCREEN 1:CLS
20 LINE (0,0)-(10,10),3,B
30 CIRCLE (5,5),5,1
40 PAINT (5,5),2,1
50 DIM IMAGE(22)
60 GET (0,0)-(10,10),IMAGE
70 DEF SEG
80 BSAVE "IMAGE.FIL",VARPTR(IMAGE(0)),88
90 ERASE IMAGE
100 DIM IMAGE(22)
110 DEF SEG
120 BLOAD "IMAGE.FIL",VARPTR(IMAGE(0))
130 PUT (100,100),IMAGE
140 LOCATE 13
-----------------------------------------------------------------
Personalized DATA
(PC Magazine Vol 5 No 20 Nov 25, 1986 User-to-User)
STAMP.BAS (PC Mag Vol 5 No 8 April 29, 1986) demonstrated how to
modify a comment permanently from within a BASIC program. It's also
possible to modify a quoted string in an assigned statement or DATA
statement, since the BASIC interpreter will set up the string variable
to point into the program itself when the string is assigned to, or
read to, a string variable.
UPDATER.BAS asks for the user's name, displaying the name that is
already loaded in the DATA statement as the default. If the user then
simply hits the Return key, the program accepts the default; otherwise
the program stores the replacement name in the DATA statement and then
saves itself. CVI is used to for the string, since this technique
avoids possible overflow errors that can result from multiplication.
Editor's Note: This kind of trick can come in handy when adding
new information on the fly, but be careful with it since it can also
write bad data over good data. You can get around this by adding a
line to the program that saves a backup "UPDATER.BAK" file to disk
before it makes any of the changes in memory and then writes the
permanently changed file.
100 'UPDATER.BAS
110 READ DUMMY$
120 PRINT "Enter your name: [";DUMMY$;"]"
130 LINE INPUT I$
140 IF I$="" THEN END ELSE I$=I$+SPACE$(19)
150 P%=VARPTR(DUMMY$)
160 L%=PEEK(P%)
170 A%=CVI(CHR$(PEEK(P%+1))+CHR$(PEEK(P%+2)))
180 FOR I%=1 TO L%
190 POKE A%+I%-1,ASC(MID$(I$,I%))
200 NEXT
210 SAVE "UPDATER
220 DATA "User name goes here"
-----------------------------------------------------------------
BASIC and the Environment
(PC Magazine Vol 5 No 20 Nov 25, 1986 PC Tutor)
You can use the undocumented feature of batch files that allows
treating environment strings as replaceable parameters. With this
you can let batch files know which device drivers are currently loaded
and to prevent running incompatible resident programs. For instance,
to load a mouse driver, your AUTOEXEC.BAT file can execute:
SET MOUSE=1
Then you can do things in batch files like:
IF "%MOUSE%"="1" some command
IF NOT "%MOUSE%"="1" some other command
Getting at the environment in BASIC is different.
Editor's Note: This is a good use of the environment, except it
doesn't work right under DOS 3.0. DOS 2.x, 3.1 and 3.2 handle it fine.
The segment address of the environment is always stored at offset
&H002C of the Program Segment Prefix (PSP) of any program. So, if you
could find the segment address of BASICA.COM's PSP (which will be
different depending on which resident programs and device drivers were
loaded), you could directly access the environment with PEEK. This
would be messy and probably involve some assembly language routines.
There's a better way, and that is to upgrade to DOS 3.1 or later.
The new BASICA 3.0 ENVIRON$ function retrieves strings from the
environment based either on the parameter name (such as "PATH") or on
a number. The small program below shows both approaches. The WHILE
loop in the first part displays the same information as the DOS SET
command executed without parameters.
10 I=1
20 WHILE ("" <> ENVIRON$(I))
30 PRINT ENVIRON$(I)
40 I=I+1
50 WEND
60 PRINT "The COMSPEC is ";ENVIRON$("COMSPEC")
-----------------------------------------------------------------
Doing a DIR in BASIC
(PC Magazine Vol 5 No 20 Nov 25, 1986 PC Tutor)
How do you read a diskette directory information into an array
from a BASIC program, and how do you invoke a Print-Screen from within
a program automatically?
Editor's Note: A very common method used by BASIC programmers for
reading the directory is no more elegant than:
1) Clear the screen with CLS
2) Do a FILES command to display a directory on the screen
3) Read the information off the screen character by character with
a combination of the LOCATE statement and teh SCREEN function. (The
SCREEN function reads characters from the screen; there is also a
SCREEN statement used for setting video modes.)
If you'd rather not have the users of your program know what you're
doing, you can use the COLOR statement to set the same foreground and
background colors so nobody can see the FILES display. (The information
is still there, of course.)
You might also consider another method using the SHELL command,
which is documented under BASIC 3.0 and works most of the time under
BASIC 2.0. The SHELL command executes another program or a DOS command
from BASIC. Your line would read:
SHELL ("DIR > DIRLIST")
This puts a normal DIR listing into a file called DIRLST. You can then
read the DIRLIST file normally and extract the information you want.
Other than these approaches, you'd probably have to use an assembly
language subroutine. This would definitely be more complex than either
of the two methods described above. BASIC is not the only high-level
language that has no built-in facility for obtaining directory
information: Turbo Pascal and Microsoft C 3.0 don't either.
Doing a Print-Screen from a BASIC program is much easier. In fact,
the BASIC 3.0 manual shows two methods for doing it in Appendix B on
assembly language subroutines. The BIOS Print Screen routine is invoked
by an Interrupt 5, which in assembly language takes just two bytes:
&HCD and &H05. An assembly language routine in BASIC needs only one
more byte, an &HCB, which is a far return back to the main BASIC
program. You can determine the bytes needed for an assembly language
routine by going into DEBUG assemble mode with the A command and
typing:
INT 5
RETF
and then listing the bytes with the D command.
To get these bytes into a BASIC listing, first DIMension an integer
array and store the assembly language code in it:
10 DIM APRTSC%(2)
20 APRTSC%(1)=&H05CD
30 APRTSC%(2)=&H90CB
Each integer can store 2 bytes. (Note that the integers are stored in
reverse order, with the most significant byte higher in memory.) The
extra &H90 at the end is a NOP instruction, which does nothing.
After the array is set up, use the VARPTR function to find the
address of the array in memory and store it in another variable:
40 PRTSC%=VARPTR(APRTSC%(1))
Now you need only CALL that variable:
50 CALL PRTSC%
and your screen will be printed.
-----------------------------------------------------------------
IBM PC One-Liner
(COMPUTE! December 1986 by Paul W. Carlson)
Programs don't have to be long to be useful. The one-line program
below can be used to entertain pre-schoolers, while teaching them the
alphabet and the computer's keyboard at the same time. Adults can
benefit from the program by gaining an increased understanding of how
characters are produced on the IBM's video display. However it's used,
the program is certainly worth the time it takes to type in the single
line.
When you run it, nothing seems to happen. Now press any key on
the keyboard. A giant character matching the key you pressed rises
from the bottom of the screen and centers itself on the display.
Press another key. The same thing happens and continues happening
until you press Ctrl-Break.
The program enlarges all the letters (uppercase and lowercase),
symbols, and punctuation that appears on the keyboard -- plus a few
that don't appear on the keycaps. If you press Ctrl along with a
letter or number key, you'll see one of the IBM's graphics characters.
Even the function keys produce results. Try pressing F1.
Despite its small size, the program contains some techniques you
may find useful in other programs.
1. The program begins by setting the segment to location $FFA6.
This is 14 bytes before the PEL (character definition) map in ROM.
The program reads your keystroke and converts it to the corresponding
ASCII code.
2. Then the program loops through eight bytes for the character,
with byte zero (the first byte) containing the bits for the top row of
the character and byte seven containing those for the bottom row. It
stores the value of the PEL map in the variable A and initializes A$
as a null string.
3. We begin to loop through the eight bits of the current byte,
resting the rightmost bit first. The variable M equals one if the bit
is set and equals zero if it's not. The value of the variable W equals
32 (the ASCII code for a blank space) if the bit is not set and equals
219 (the ASCII code for a solid block) if the bit is set. Either three
blanks or three solid blocks are added to the beginning of A$. Then
the program shifts all bits in the current byte by subtracting the
value of the rightmost bit and dividing by two. This step is repeated
for each bit of the current byte.
4. The next step is to print A$ preceded by 28 blanks. This is
done twice to double the character's height. Then the program
branches back to step 2 and repeats the process for each byte of the
PEL map that defines the character. After the last byte of the PEL
map has been processed, we print two blank lines and return to step 1
to wait for another keypress.
Experienced programmers may notice that the code could be made
even more compact. Some statements could be combined, but this would
result in parentheses several levels deep, making the program more
difficult to understand.
1 KEY OFF:DEF SEG=&HFFA6:L$=INPUT$(1):N=ASC(L$):CLS:LOCATE 24,1,0:FOR
L=0 TO 7:A=PEEK(N*8+L+14):A$="":FOR J=0 TO 7:M=A AND 1:W=32+M*187:A$
=CHR$(W)+CHR$(W)+CHR$(W)+A$:A=(A-M)/2:NEXT J:PRINT SPC(28)A$:PRINT
SPC(28)A$:NEXT L:PRINT:PRINT:GOTO 1
(NOTE: To save and run this one-line program, copy it out and make it
one continuous line by removing the carriage returns from the ends of
the lines.)
-----------------------------------------------------------------
Faster Slide Show
(PC Magazine Vol 5 No 21 Dec 9, 1986 User-to-User)
This technique produces a smooth BASIC slide show program. The
BASIC BLOADer normally reads a graphics screen off a disk directly to
the screen buffer. This approach gives a very slow (7.5-second) and
messy screen update. However, using a combination of the PUT statement
and VARPTR function with BLOAD creates a fast and smooth slide show
program. Use these statements to create screen data files:
100 DIM A(4000)
.
. (Screen-creating code)
.
200 GET (0,0)-(319,199),A
210 DEF SEG
220 ADDRESS=VARPTR(A(0))
230 BSAVE "SCR1.",ADDRESS,16004
Then use the following statements to display the graphics screens:
100 DIM A(4000)
110 ADDRESS=VARPTR(A(0))
120 BLOAD "SCR1.",ADDRESS
130 PUT (0,0),A,PSET
This method updates the screen in less than a second. It still
takes about 7.5 seconds to BLOAD the graphics information into memory,
but you can display one screen while the next one loads. The full
technique is implemented in DEMOLOAD.BAS:
100 'DEMOLOAD.BAS
110 DEF FNS$(Z)=MID$(STR$(Z),2)
120 SCREEN 1:CLS:KEY OFF:DIM A(4000)
130 PRINT "First we'll make 3 screens"
140 PRINT "(Hit any key to continue)"
150 WHILE INKEY$="":WEND:CLS
160 FOR B=1 TO 3:FOR C=1 TO 23
170 PRINT STRING$(40,48+B);:NEXT
180 CIRCLE (160,92),60,B,,,4/5
190 PAINT (160,92),B
200 GET (0,0)-(319,199),A
210 DEF SEG:ADDRESS=VARPTR(A(0))
220 BSAVE "SCR"+FNS$(B),ADDRESS,16004
230 CLS:NEXT
240 '
250 PRINT "Now we'll quick-load them"
260 PRINT "(Hit any key to continue)"
270 WHILE INKEY$="":WEND
280 ADDRESS=VARPTR(A(0))
290 BLOAD "SCR1",ADDRESS
300 PUT (0,0),A,PSET
310 BLOAD "SCR2",ADDRESS
320 PUT (0,0),A,PSET
330 BLOAD "SCR3",ADDRESS
340 PUT (0,0),A,PSET
-----------------------------------------------------------------
BASICA 3.2 Bug
(PC Magazine Vol 5 No 22 Dec 23, 1986 User-to-User)
DOS 3.2 BASICA.COM does not save files efficiently. If a file's
size is reduced, the space allocated is fixed at the largest previously
saved size. This is not true for all other IBM (Microsoft) BASICs,
including DOS 3.2 BASIC.COM. The solution is to set up a macro (based
on the filename being imbedded in the program at a fixed location) to
first delete the current file before the updated version is saved.
SmartKey is a big help here.
Editor's Note: Another solution is to add two lines to the
beginning of your program:
101 KILL"filename
102 SAVE"filename
(substituting the actual name of your BASICA program for filename).
Each time you run it, this code will delete the existing version and
save the subsequent one.
Actually, when you chop a large program down to a smaller one,
BASICA 3.2 not only keeps the file size the same but actually seems to
retain the discarded part of the program. To see this in action
(assuming you're using BASIC 3.2 only), run LONG.BAS to create a 10K
file:
100 'CREATE.BAS -- creates a long file
110 DEF FNST$(Z)=MID$(STR$(Z),2+(Z<0))
120 OPEN "LONG.BAS" FOR OUTPUT AS #1
130 FOR A=100 TO 5000 STEP 10
140 PRINT #1,FNST$(A);" REM DUMMY TEXT"
150 NEXT:CLOSE:END
Get into DOS and note the file size. Then get into BASICA 3.2,
load LONG.BAS, and issue the command to get rid of most of the file's
contents:
DELETE 200-
Save the shorter file, and get into DOS and you'll see that the tiny
file has the same size as the older, larger one. Then get into DEBUG,
and start leaning on the D key and you'll see that the part of the file
you deleted is still there.